/*
 * Copyright (C) 2010, Funcom AS, All Rights Reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  @authors
 *  Svein Gunnar Larsen <sveingunnarlarsen@gmail.com>
 *  Erik Thune Lund <culex.eriklund@gmail.com>
 *  Michel Krohn-Dale <kronicz@gmail.com>
 */

package com.funcom.peeler.peelable;

import com.funcom.peeler.PeelStyleSheet;
import com.funcom.peeler.symbol.Symbol;
import com.jmex.bui.BComponent;
import com.jmex.bui.util.Rectangle;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.util.HashSet;

public class PeelComponent {

    BComponent component;
    PeelContainer parent;
    PeelRoot root;
    String element_name = Symbol.Node.component;

    HashSet< PeelComponent > group;

    boolean locked = false;

    public PeelComponent() {
        this( new BComponent() );
    }

    protected PeelComponent( BComponent component ) {
        this.component = component;
    }

    public PeelContainer getParent() {
        return parent;
    }

    protected void setParent( PeelContainer new_parent ) {
        parent = new_parent;
    }

    protected Element createPeeledInfo( Document doc ) {

        Element element = doc.createElement( element_name );

        return getPeeledInfo( element );
    }

    protected Element getPeeledInfo( Element element ) {

        element.appendChild( getBoundsInfo( element ) );

        if ( component.getName() != null ) element.setAttribute( Symbol.Attr.name, component.getName() );

        element.setAttribute( Symbol.Attr.style, component.getStyleClass() );

        Element properties = getPropertiesInfo( element );
        if ( properties != null ) element.appendChild( properties );

        if ( isHidden() ) {
            element.setAttribute( Symbol.Attr.hide, Symbol.Toggle.enabled );
        }
        else {
            element.setAttribute( Symbol.Attr.hide, Symbol.Toggle.disabled );
        }

        if ( isLocked() ) {
            element.setAttribute( Symbol.Attr.lock, Symbol.Toggle.enabled );
        }
        else {
            element.setAttribute( Symbol.Attr.lock, Symbol.Toggle.disabled );
        }

        return element;
    }

    public PeelRoot getRoot() {
        return root;
    }

    public void setRoot( PeelRoot root ) {

        if ( root == null ) return;

        root.addToMap( this );
        this.root = root;
    }

    public Element peel( Document doc ) {

        Element peeled_element = createPeeledInfo( doc );
        return peeled_element;
    }

    /* Send in an Element from a Peelerfile, construct this PeelComponent plus any children,
        send back the list of constructed PeelComponents */
    public void unpeel( Element element ) {

        unpeelInfo( element );
    }

    public synchronized BComponent getComponent() {
        return component;
    }

    public boolean isLocked() {
        return locked;
    }

    public void setLocked(boolean val) {
        locked = val;
    }

    public boolean isHidden() {
        return !component.isVisible();
    }

    public void setHidden(boolean val) {
        component.setVisible( !val );
    }

    public boolean hasGroup() {
        return group != null && group.contains( this );
    }

    public HashSet< PeelComponent > getGroup() {

        if ( !hasGroup() ) {
            group = new HashSet< PeelComponent >();
            group.add( this );
        }

        return group;
    }

    public void addToGroup( HashSet< PeelComponent > group ) {
        removeFromGroup();
        this.group = group;
        this.group.add( this );
    }

    public void removeFromGroup() {

        if ( hasGroup() ) {
            group.remove( this );
            group = null;
        }
    }

    private Element getBoundsInfo( Element parent ) {

        Rectangle bounds = component.getBounds();

        Element rectangle_element = parent.getOwnerDocument().createElement( Symbol.Node.rectangle );
        rectangle_element.setAttribute( Symbol.Attr.pos_x, String.valueOf( bounds.x ) );
        rectangle_element.setAttribute( Symbol.Attr.pos_y, String.valueOf( bounds.y ) );
        rectangle_element.setAttribute( Symbol.Attr.width, String.valueOf( bounds.width ) );
        rectangle_element.setAttribute( Symbol.Attr.height, String.valueOf( bounds.height ) );

        return rectangle_element;
    }

    protected Element getPropertiesInfo( Element parent ) {

        Element properties = parent.getOwnerDocument().createElement( Symbol.Node.properties );

        if ( component.getProperty( Symbol.Attr.locale_text ) != null ) {
            properties.setAttribute( Symbol.Attr.locale_text, (String)component.getProperty( Symbol.Attr.locale_text ) );
        }

        return properties;
    }

    protected void unpeelProperties( Element element ) {

        Element properties = (Element)element.getElementsByTagName( Symbol.Node.properties ).item( 0 );
        if ( properties == null ) return;

        if ( properties.hasAttribute( Symbol.Attr.locale_text ) )
            component.setProperty( Symbol.Attr.locale_text, properties.getAttribute( Symbol.Attr.locale_text ) );
    }

    protected void unpeelInfo( Element element ) {

        unpeelBounds( element );

        if ( element.hasAttribute( Symbol.Attr.name ) ) component.setName( element.getAttribute( Symbol.Attr.name ) );

        if ( element.hasAttribute( Symbol.Attr.style ) ) component.setStyleClass( element.getAttribute( Symbol.Attr.style ) );

        unpeelProperties( element );

        if ( element.hasAttribute( Symbol.Attr.hide ) ) {
            if ( element.getAttribute( Symbol.Attr.hide ).equals( Symbol.Toggle.enabled ) )
                setHidden( true );
        }

        if ( element.hasAttribute( Symbol.Attr.lock ) ) {
            if ( element.getAttribute( Symbol.Attr.lock ).equals( Symbol.Toggle.enabled ) )
                setLocked( true );
        }
    }

    private void unpeelBounds( Element element ) {

        Element rectangle = (Element)element.getElementsByTagName( Symbol.Node.rectangle ).item( 0 );
        if ( rectangle == null ) return;

        int pos_x = Integer.parseInt( rectangle.getAttribute( Symbol.Attr.pos_x ) );
        int pos_y = Integer.parseInt( rectangle.getAttribute( Symbol.Attr.pos_y ) );
        int width = Integer.parseInt( rectangle.getAttribute( Symbol.Attr.width ) );
        int height = Integer.parseInt( rectangle.getAttribute( Symbol.Attr.height ) );

        component.setBounds( pos_x, pos_y, width, height );
    }

    public PeelStyleSheet getStyleSheet() {
        if (getComponent().getWindow() == null) return null;
        return (PeelStyleSheet)getComponent().getWindow().getStyleSheet();
    }

    public void detach() {
        if ( getParent() != null ) {
            getParent().removeChild( this );
        }
    }
}
